// src/theme.js
import React, { createContext, useContext, useEffect, useState, useMemo } from 'react';

/**
 * 主题上下文
 * 用于在整个应用程序中共享主题状态和函数
 */
const ThemeContext = createContext();

/**
 * 可用的主题类型
 */
export const THEMES = {
  LIGHT: 'light',  // 浅色主题
  DARK: 'dark',    // 深色主题
  SYSTEM: 'system' // 跟随系统主题
};

/**
 * 主题提供者组件
 * 负责管理应用的主题状态并将其分发给子组件
 * 
 * @param {Object} props - 组件属性
 * @param {React.ReactNode} props.children - 子组件
 * @returns {JSX.Element} - 主题提供者组件
 */
export function ThemeProvider({ children }) {
  // 从本地存储加载保存的主题
  const [theme, setTheme] = useState(() => {
    // 尝试从localStorage获取保存的主题，默认为系统主题
    return localStorage.getItem('theme') || THEMES.SYSTEM;
  });
  
  // 用于跟踪系统深色模式的状态
  const [systemIsDark, setSystemIsDark] = useState(() => 
    window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
  );

  /**
   * 更新主题设置
   * @param {string} newTheme - 新的主题设置（'light', 'dark', 或 'system'）
   */
  const updateTheme = (newTheme) => {
    setTheme(newTheme);
    localStorage.setItem('theme', newTheme);
  };

  // 处理系统主题变化的副作用
  useEffect(() => {
    // 创建媒体查询以检测系统深色模式
    const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    
    /**
     * 应用当前主题到DOM
     * 根据主题设置和系统偏好设置调整data-theme属性
     */
    const applyTheme = () => {
      const root = document.documentElement;
      if (theme === THEMES.SYSTEM) {
        // 如果选择了"系统"主题，则根据系统的深色模式偏好设置主题
        const systemTheme = darkModeMediaQuery.matches ? THEMES.DARK : THEMES.LIGHT;
        root.setAttribute('data-theme', systemTheme);
      } else {
        // 直接应用用户选择的主题
        root.setAttribute('data-theme', theme);
      }
    };
    
    // 首次应用主题
    applyTheme();
    
    /**
     * 系统主题变化事件处理函数
     * 当系统主题改变时重新应用主题并更新systemIsDark状态
     */
    const handleSystemThemeChange = (e) => {
      setSystemIsDark(e.matches);
      if (theme === THEMES.SYSTEM) {
        applyTheme();
      }
    };
    
    // 监听系统主题变化
    darkModeMediaQuery.addEventListener('change', handleSystemThemeChange);
    
    // 清理函数 - 移除事件监听器
    return () => {
      darkModeMediaQuery.removeEventListener('change', handleSystemThemeChange);
    };
  }, [theme]); // 依赖于theme状态，当theme改变时重新运行

  /**
   * 获取当前活动主题
   * @returns {string} - 当前激活的主题 ('light' 或 'dark')
   */
  const getActiveTheme = () => {
    if (theme !== THEMES.SYSTEM) {
      return theme;
    }
    
    // 对于系统主题设置，返回当前系统主题
    return systemIsDark ? THEMES.DARK : THEMES.LIGHT;
  };

  // 使用useMemo缓存activeTheme，减少不必要的重新计算
  const activeTheme = useMemo(() => getActiveTheme(), [theme, systemIsDark]);

  // 创建传递给上下文的值对象
  const contextValue = {
    theme,           // 当前主题设置
    setTheme: updateTheme,  // 更新主题的函数
    activeTheme,     // 当前激活的主题
  };

  // 提供主题上下文给子组件
  return (
    <ThemeContext.Provider value={contextValue}>
      {children}
    </ThemeContext.Provider>
  );
}

/**
 * 自定义Hook: 使用主题
 * 允许组件访问和操作主题状态
 * 
 * @returns {Object} 包含主题状态和相关函数的对象
 * @property {string} theme - 当前主题设置 ('light', 'dark', 或 'system')
 * @property {Function} setTheme - 更新主题的函数
 * @property {string} activeTheme - 当前激活的主题 ('light' 或 'dark')
 * @property {Function} toggleTheme - 在浅色和深色主题之间切换的便捷函数
 */
export function useTheme() {
  // 获取主题上下文
  const context = useContext(ThemeContext);
  
  // 上下文检查 - 确保在ThemeProvider内部使用
  if (context === undefined) {
    throw new Error('useTheme 必须在 ThemeProvider 内部使用');
  }
  
  /**
   * 主题切换函数 - 在浅色和深色主题之间切换
   * 如果当前是系统主题，则会根据当前系统主题切换到相反的特定主题
   */
  const toggleTheme = () => {
    const { theme, activeTheme, setTheme } = context;
    
    if (activeTheme === THEMES.LIGHT) {
      // 如果当前是浅色，切换到深色
      setTheme(THEMES.DARK);
    } else {
      // 如果当前是深色，切换到浅色
      setTheme(THEMES.LIGHT);
    }
  };
  
  // 返回扩展后的上下文，包括toggleTheme函数
  return {
    ...context,
    toggleTheme
  };
}

// 导出ThemeProvider作为默认导出
export default ThemeProvider; 